<?php
class Application extends AbstractApplication
{
	private $properties = array(
		"config", "services", "user"
	);

	private $coreClasses = array(
		"Debugger", "Core", "CoreLib", "UserLib", "DynamicObject", "AbstractResponse",
		"ControllerBase", "ViewBase", "Services", "Session", "ServiceResponse", "Response",
		"Context", "RequestHandler", "Exceptions", "ServerException"
	);

	private $responseString = "";

	private $response = null;


	public function __construct( ContextLoader $loader )
	{
		// Guarda el cargador de contexto actual.
		//
		$this->contextLoader = $loader;
		$loader->application = $this;

		// Carga la configuración del contexto.
		//
		require_once( $loader->contextConfig );

		$configClass = $this->getClassName( $loader->contextConfig );

		$loader->configure = new $configClass();

		$this->checkConfigure();

		$configure = $loader->configure;
		$classLoader = $loader->classLoader;

		$classLoader->setEnvironVar( "CONTEXT_ROOT", $configure->contextRoot );
		$classLoader->setEnvironVar( "APP_ROOT", $configure->appRoot );

		// Agrega los directorios del sistema al classpath.
		//
		$configure->includePath = array_merge( $configure->includePath,
			array(
				"core"       => "{CONTEXT_ROOT}/core/", 		// Directorio del núcleo.
				"reflection" => "{CONTEXT_ROOT}/reflection/",	// Directorio de la API de Reflection.
				"exceptions" => "{CONTEXT_ROOT}/exceptions/",	// Directorio de excepciones.
				"compat"     => "{CONTEXT_ROOT}/compat/"
			)
		);

		$configure->includePath = $classLoader->expandEnvironVars( $configure->includePath );

		// Agrega los directorios del archivo de configuración a los includes.
		//
		$classLoader->addContextPaths( $configure->includePath );

		$exceptionDir = $configure->includePath["exceptions"];

		// Carga las clases del sistema.
		//
		$classLoader->loadClasses( $this->coreClasses );
		$classLoader->loadClasses( $configure->userLibs );
		$classLoader->loadClasses( $configure->contextLibs );

		// Carga las excepciones.
		//
		$classLoader->loadClassesFromDir( $exceptionDir );

		// Inicializa el controlador de excepciones predererminado.
		//
		if( is_object($loader->globalExceptionHandler) )
		{
			$loader->globalExceptionHandler->attachHandler();
		}

		// Ejecuta la aplicación.
		//
		$this->responseString = RequestHandler::execute( $this );

		$this->loadComplete = true;
	}

	/**
	 * Carga el modelo de base de datos.
	 */
	public function loadModel( $loaderClass )
	{
		// Verficia si está cargado, y en tal caso
		// no vuelve a agregar las librerías.
		//
		if ( $this->modelLoaded ) {
			return(false);
		}

		$configure = $this->contextLoader->configure;
		$beanClass = $configure->ormLoaderClass;

		if ( $this->loadLibrary( $beanClass ) )
		{
			$this->model = new $loaderClass(
				$configure->ormConfigClass, $this->contextLoader->classLoader
			);

			$this->modelLoaded = true;
		}

		return(true);
	}

	/**
	 * Agrega una librería al sistema.
	 */
	public function loadLibrary($libFile, $userLib = false)
	{
		if ( !ClassLoader::getInstance()->loadClass( $libFile ) )
		{
			if ( !$userLib )
			{
				throw new LibMissingException( "Configure: un archivo del sistema no existe ($libFile)." );
			}
		}

		return(true);
	}

	public function peekResponse()
	{
		if ( RequestHandler::$responseVoid )
			return;

		return( $this->responseString );
	}


	/**
	 * Devuelve un objeto AbstractModel que representa al modelo cargado.
	 */
	public function getModel()
	{
		$this->loadModel( $this->contextLoader->configure->ormLoaderClass );

		return( $this->model );
	}

	/**
	 * Devuelve el cargador de contexto de la aplicación.
	 */
	public function getContextLoader()
	{
		return( $this->contextLoader );
	}


	/**
	 * Verifica la integridad del archivo de configuración.
	 */
	private function checkConfigure()
	{
		$configure = $this->contextLoader->configure;

		if ( is_null( $configure->includePath ) )
			die("El archivo de configuración no existe o su formato es incorrecto.");

		for ( $i = 0; $i < count($this->properties); $i++ )
		{
			$varName = $this->properties[$i];

			if ( !isset( $configure->includePath[$varName] ) ) {
				die( "Configure: el directorio '$varName' no está definido." );
			}
		}
	}

	private function getClassName($libFile)
	{
		$slashPos = strrpos($libFile, "/");

		if ( $slashPos > -1 )
			$libName = substr($libFile, $slashPos + 1);
		else
			$libName = substr($libFile, 1);

		$className = str_replace(".php", "", $libName );

		return($className);
	}

	/**
	 * Devuelve el cargador de contexto de la aplicación.
	 */
	public function getResponse()
	{

	}

	/**
	 * Devuelve el objeto AbstractRequest que representa a la peticion actual.
	 */
	public function getRequest()
	{

	}

}

?>
